// Copyright (C) ZHENG Zhong <heavyzheng nospam-at gmail D0T com>
//
// $Id: callbacks.cpp 318 2009-03-02 14:03:21Z heavyzheng $
//

#ifndef ZZHENG_XML_SOURCE
#define ZZHENG_XML_SOURCE
#endif // ZZHENG_XML_SOURCE

#include <zzheng/xml/dom/libxml2/callbacks.hpp>
#include <zzheng/xml/dom/libxml2/attribute.hpp>
#include <zzheng/xml/dom/libxml2/element.hpp>
#include <zzheng/xml/dom/libxml2/text.hpp>
#include <zzheng/xml/dom/libxml2/comment.hpp>

#include <libxml/tree.h>
#include <cassert>

namespace zzheng {
namespace xml {
namespace dom {
namespace libxml2_ {

    namespace {

        template<class T>
        void delete_private(xmlNode* px) {
            T* wrapper = static_cast<T*>(px->_private);
            assert(wrapper != 0);
            if (wrapper != 0) {
                delete wrapper;
                px->_private = 0;
            }
        }

    } // anonymous namespace

    ////////////////////////////////////////////////////////////////////////////////////////////////

    void on_node_construct(xmlNode* px) {
        switch (px->type) {
        case XML_DOCUMENT_NODE:
            // Do nothing: the document wrapper will be created by the parser.
            break;
        case XML_ATTRIBUTE_NODE:
            px->_private = new attribute(px);
            break;
        case XML_ELEMENT_NODE:
            px->_private = new element(px);
            break;
        case XML_TEXT_NODE:
        case XML_CDATA_SECTION_NODE:
            px->_private = new text(px);
            break;
        case XML_COMMENT_NODE:
            px->_private = new comment(px);
            break;
            //case XML_PI_NODE:
            //case XML_DTD_NODE:
            //case XML_ENTITY_REF_NODE:
        default:
            // TODO: Unsupported node types.
            px->_private = 0;
            break;
        }
    }

    void on_node_destruct(xmlNode* px) {
        switch (px->type) {
        case XML_DOCUMENT_NODE:
            // Private pointer should have been set to null.
            assert(px->_private == 0 && "Document node should have null _private.");
            break;
        case XML_ATTRIBUTE_NODE:
            delete_private<attribute>(px);
            break;
        case XML_ELEMENT_NODE:
            delete_private<element>(px);
            break;
        case XML_TEXT_NODE:
        case XML_CDATA_SECTION_NODE:
            delete_private<text>(px);
            break;
        case XML_COMMENT_NODE:
            delete_private<comment>(px);
            break;
        default:
            // TODO: Unsupported node types.
            assert(px->_private == 0 && "Unsupported node should have null _private.");
            break;
        }
    }

    void register_callbacks() {
        static bool registered = false;
        if (!registered) {
            xmlRegisterNodeDefault        ( &on_node_construct );
            xmlDeregisterNodeDefault      ( &on_node_destruct  );
            xmlThrDefRegisterNodeDefault  ( &on_node_construct );
            xmlThrDefDeregisterNodeDefault( &on_node_destruct  );
            registered = true;
        }
    }

} // namespace zzheng::xml::dom::libxml2_
} // namespace zzheng::xml::dom
} // namespace zzheng::xml
} // namespace zzheng


